using System.Collections.Generic;
using GameServer.ShootingGame.RenderableClasses;
using System;
using System.Drawing;

namespace GameServer.ShootingGame.Physics.CollisionReactionClasses.Base
{


    //Each collider will have a ref to an instance of this type.
    //This class maintains a list of general and specific collision types with the various kinds of other objects.
    //Any object type that can sometimes have a different state that affects reactions should be added as a separate collision type
    //for e.g. PLAYER and SHILEDED_PLAYER will be considered as two completely different colliding objects by a ORDINANCE collider.


    public enum Colliders { PLAYER, ORDINANCE, WALL };

    public class CollisionEffects
    {

        public enum CollisionFX { BOUNCE, EXPIRE, PERPENDICULAR_ZERO, TAKE_DAMAGE, NONE };

        private const string PARAMETER_NAME = "parameter_name";
        private const string PARAM_RECT = "param_rect";
        private const string PARAM_CIRCLE = "param_circle";
        //		public static const string PARAM_WALL_RECT : String = "param_wall_rect";

        public List<CollisionFX> reactions_ToWall;
        public List<CollisionFX> reactions_ToPlayer;
        public List<CollisionFX> reactions_ToOrdinance;

        public GameObject owner;
        private Stack<Object> unresolvedCollisions;
        public Colliders ownerColliderType;
        public RectangleF parameterObject;

        public CollisionEffects(GameObject owner, Colliders ownerColliderType, List<CollisionFX> reactions_ToWall, List<CollisionFX> reactions_ToPlayer, List<CollisionFX> reactions_ToOrdinance)
        {
            this.owner = owner;
            this.ownerColliderType = ownerColliderType;
            if (reactions_ToWall == null)
                reactions_ToWall = new List<CollisionFX>(1);
            if (reactions_ToPlayer == null)
                reactions_ToPlayer = new List<CollisionFX>(1);
            if (reactions_ToOrdinance == null)
                reactions_ToOrdinance = new List<CollisionFX>(1);
            this.reactions_ToWall = reactions_ToWall;
            this.reactions_ToPlayer = reactions_ToPlayer;
            this.reactions_ToOrdinance = reactions_ToOrdinance;
            unresolvedCollisions = new Stack<object>();
            parameterObject = RectangleF.Empty;
        }

        public void ResolveCollision()
        {
            object obj = null;
            parameterObject = RectangleF.Empty;
            if (unresolvedCollisions.Count > 0)
                obj = unresolvedCollisions.Pop();

            if (obj is RectangleF)
            {
                parameterObject = (RectangleF)obj;
                React(unresolvedCollisions.Pop() as GameObject);
            }
            else
                React(obj as GameObject);
        }

        virtual protected void React(GameObject collidee)
        {
            CollisionEffects collidee_CollisionEffects = null;
            if (collidee.collisionEffects != null)
            {
                collidee_CollisionEffects = collidee.collisionEffects;
                switch (collidee_CollisionEffects.ownerColliderType)
                {
                    case Colliders.WALL:
                        ReactToWall(collidee);
                        break;
                    case Colliders.PLAYER:
                        ReactToPlayer(collidee);
                        break;
                    case Colliders.ORDINANCE:
                        reactToOrdinance(collidee);
                        break;
                    default:
                        break;
                }
            }
        }

        virtual protected void ReactToPlayer(GameObject collidee)
        {
            if (reactions_ToPlayer.Count > 0)
            {
                int i;
                int n = reactions_ToPlayer.Count;
                for (i = 0; i < n; i++)
                {
                    switch (reactions_ToPlayer[i])
                    {
                        case CollisionFX.BOUNCE:
                            bounce(collidee);
                            break;
                        case CollisionFX.EXPIRE:
                            expire();
                            break;
                        case CollisionFX.PERPENDICULAR_ZERO:
                            perpendicular_Zero(collidee);
                            break;
                        default:
                            break;
                    }
                }
            }
        }

        virtual protected void ReactToWall(GameObject collidee)
        {
            if (reactions_ToWall.Count > 0)
            {
                int i;
                int n = reactions_ToWall.Count;
                for (i = 0; i < n; i++)
                {
                    switch (reactions_ToWall[i])
                    {
                        case CollisionFX.BOUNCE:
                            bounce(collidee);
                            break;
                        case CollisionFX.EXPIRE:
                            expire();
                            break;
                        case CollisionFX.PERPENDICULAR_ZERO:
                            perpendicular_Zero(collidee);
                            break;
                        default:
                            break;
                    }
                }
            }
        }

        virtual protected void reactToOrdinance(GameObject collidee)
        {
            if (ownerColliderType == Colliders.WALL)
                return;

            if (reactions_ToOrdinance.Count > 0)
            {
                int i;
                int n = reactions_ToOrdinance.Count;
                for (i = 0; i < n; i++)
                {
                    switch (reactions_ToOrdinance[i])
                    {
                        case CollisionFX.BOUNCE:
                            bounce(collidee);
                            break;
                        case CollisionFX.EXPIRE:
                            expire();
                            break;
                        case CollisionFX.PERPENDICULAR_ZERO:
                            perpendicular_Zero(collidee);
                            break;
                        case CollisionFX.TAKE_DAMAGE:
                            take_Damage(collidee);
                            break;
                        default:
                            break;
                    }
                }
            }
        }

        virtual public void AddCollision(GameObject gameObject)
        {
            AddCollision(gameObject, null);
        }

        virtual public void AddCollision(GameObject gameObject, Object parameter)
        {
            unresolvedCollisions.Push(gameObject);
            if (parameter != null)
            {
                unresolvedCollisions.Push(parameter);
            }
        }

        virtual protected void bounce(GameObject collidee)
        {

        }

        virtual protected void expire()
        {
            owner.IsExpired = true;
        }

        virtual protected void perpendicular_Zero(GameObject collidee)
        {
            if (parameterObject != RectangleF.Empty)
            {
                RectangleF rect = parameterObject;
                //					trace("hitSomething");
                if (rect.Left > owner.xPosition && rect.Right > owner.xPosition)
                {
                    if ((owner as MobileObject).ThrustX > 0)
                    {
                        (owner as MobileObject).ThrustX = 0;
                        owner.xPosition = rect.Left - owner.CollidablePart.Width / 2.0;
                        //							trace("hitRight");
                    }
                    //						trace((owner as MobileObject).ThrustX);
                }
                if (rect.Right < owner.xPosition && rect.Left < owner.xPosition)
                {
                    if ((owner as MobileObject).ThrustX < 0)
                    {
                        (owner as MobileObject).ThrustX = 0;
                        owner.xPosition = rect.Right + owner.CollidablePart.Width / 2.0;
                        //							trace("hitLeft");
                    }
                }

                if (rect.Top > owner.yPosition && rect.Bottom > owner.yPosition)
                {
                    if ((owner as MobileObject).ThrustY > 0)
                    {
                        (owner as MobileObject).ThrustY = 0;
                        owner.yPosition = rect.Top - owner.CollidablePart.Height / 2.0;
                        //							trace("hitbottom");
                    }
                }
                if (rect.Top < owner.yPosition && rect.Bottom < owner.yPosition)
                {
                    if ((owner as MobileObject).ThrustY < 0)
                    {
                        (owner as MobileObject).ThrustY = 0;
                        owner.yPosition = rect.Bottom + owner.CollidablePart.Height / 2.0;
                    }
                    //						trace("hitTop");
                }
            }
        }

        virtual protected void take_Damage(GameObject collidee)
        {
            owner.HitPoints -= (int)((collidee as Ordinance).weaponInfo.damage);
        }


    }
}
